/*
 *  Copyright 2012, Tera-soft Co., Ltd.  All right reserved.
 *
 *  THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF TERA-SOFT CO.,
 *  LTD.  THE CONTENTS OF THIS FILE MAY NOT BE DISCLOSED TO THIRD
 *  PARTIES, COPIED OR DUPLICATED IN ANY FORM, IN WHOLE OR IN PART,
 *  WITHOUT THE PRIOR WRITTEN PERMISSION OF TERA-SOFT CO., LTD
 *
 */
package com.tera.util;

import java.beans.PropertyDescriptor;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URLDecoder;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.beanutils.PropertyUtils;

import com.tera.sys.exception.PageBoleanValueException;

/**
 * @author Wallace chu
 *
 */
public class BeanUtils extends PropertyUtils {

    /**
     * wrap org.apache.commons.beanutils.BeanUtils.cloneBean(bean); throw a RuntimeException when Exception occurs
     * @param bean bean
     * @return Object
     */
    public static Object cloneBean(Object bean) {
        try {
            return org.apache.commons.beanutils.BeanUtils.cloneBean(bean);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * wrap org.apache.commons.beanutils.PropertyUtils.getProperty(); throw
     * a RuntimeException when Exception occurs
     * @param bean bean
     * @param property property
     * @return Object
     */
    public static Object getProperty(Object bean, String property) {
        Object value = null;
        try {
            value = PropertyUtils.getProperty(bean, property);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
        return value;
    }

    /**
     * wrap org.apache.commons.beanutils.PropertyUtils.setProperty(); throw
     * a RuntimeException when Exception occurs
     * @param bean bean
     * @param property property
     * @param value value
     */
    public static void setProperty(Object bean, String property, Object value) {
        try {
            org.apache.commons.beanutils.BeanUtils.setProperty(bean, property, value);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * compare two Object to see whether they are equal
     * @param bean1 bean1
     * @param bean2 bean2
     * @return boolean
     */
    @SuppressWarnings("unchecked")
	public static boolean equals(Object bean1, Object bean2) {
        if (bean1 == null && bean2 == null) {
            return true;
        }

        try {
            if (bean1.getClass().equals(bean2.getClass())) {
                if (bean1 == bean2) {
                	return true;
                }
                Map map1 = BeanUtils.describe(bean1);
                Map map2 = BeanUtils.describe(bean2);
                return map1.equals(map2);
            }
        } catch (Exception e) {
            /*
             * catch bean1 or bean2 NullPointException catch
             * BeanUtils.describe() exception catch BeanUtils.describe()
             * returned null map exception
             */
            return false;
        }

        return false;
    }

    /**
     * @see toString(Object bean, List travelledList)
     * @param bean bean
     * @return String
     */
    public static String toString(Object bean) {
        return toString(bean, null);
    }

    /**
     * toString(Object bean, List travelledList)
     * @param bean bean
     * @param travelledList travelledList
     * @return String
     */
    @SuppressWarnings("unchecked")
	public static String toString(Object bean, List travelledList) {
        if (bean == null) {
            return "null";
        }

        if (travelledList == null) {
            travelledList = new Vector();
        }

        StringBuffer sb = new StringBuffer();
        sb.append("<javabean class=\"" + bean.getClass().getName() + "\">"
                + "\n");

        PropertyDescriptor[] propDescriptors = BeanUtils
                .getPropertyDescriptors(bean);

        for (int i = 0; i < propDescriptors.length; i++) {
            try {
                String propName = propDescriptors[i].getName();
                Class propClass = propDescriptors[i].getPropertyType();
                Object propValue = BeanUtils.getProperty(bean, propName);
                if (propValue.getClass().isPrimitive()
                        || (propValue.getClass().getName()
                                .startsWith("java.lang"))
                        || (propValue.getClass().getName()
                                .startsWith("java.util.Date"))) {
                    if (propValue != null) {
                        propValue = propValue.toString();
                    }
                    sb.append("<property name=\"" + propName + "\" class=\""
                            + propClass.getName() + "\">");
                    sb.append(propValue);
                    sb.append("</property>\n");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        sb.append("</javabean>" + "\n");

        return sb.toString();
    }

    /**
     * copyProperties
     * @param desBean desBean
     * @param srcBean srcBean
     * @param propMap propMap
     */
    @SuppressWarnings("unchecked")
	public static void copyProperties(Object desBean, Object srcBean,
            HashMap propMap) {
        try {
            Object tempBean = BeanUtils.cloneBean(desBean);

            Iterator iterator = propMap.keySet().iterator();
            while (iterator.hasNext()) {
                String srcPropName = (String) iterator.next();
                String desPropName = (String) propMap.get(srcPropName);
                PropertyUtils.setProperty(tempBean, desPropName, PropertyUtils
                        .getProperty(srcBean, srcPropName));
            }

            BeanUtils.copyProperties(desBean, tempBean);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * copyProperties
     * @param dest dest
     * @param src src
     */
    public static void copyProperties(Object dest, Object src) {
        try {
            org.apache.commons.beanutils.BeanUtils.copyProperties(dest, src);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * newInstance
     * @param clazz clazz
     * @return Object
     */
    @SuppressWarnings("unchecked")
	public static Object newInstance(Class clazz) {
        Object bean = null;
        try {
            bean = clazz.newInstance();
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
        return bean;
    }
    /**
     * 从request中创建Bean
     * @param clazz Class
     * @param request httpserleterequest
     * @return Object
     * @throws PageBoleanValueException exception
     */
    @SuppressWarnings("unchecked")
    public static Object newRequestBean(Class clazz,
    		HttpServletRequest request) throws PageBoleanValueException {

		Object obj = newInstance(clazz);
		Field[] fields = clazz.getDeclaredFields();
		System.out.println(fields.length);
		for (Field field : fields) {
			String pro = request.getParameter(field.getName());
			if (null != pro) {

				field.setAccessible(true);
				try {
					if (int.class.equals(field.getType()) || Integer.class.equals(field.getType()))
					{
						int parseData = 0;
						if (pro != null && pro.toString().matches("\\d+")) {
							parseData = Integer.parseInt(pro.toString());
						}
						field.setInt(obj, parseData);
					} else if (long.class.equals(field.getType()) || Long.class.equals(field.getType()))
					{
						long parseData = 0L;
						if (pro != null && pro.toString().matches("\\d+")) {
							parseData = Long.parseLong(pro.toString());
						}
						field.setLong(obj, parseData);
					} else if (float.class.equals(field.getType()) || Float.class.equals(field.getType()))
					{
						float parseData = 0.0f;
						if (pro != null && pro.toString().matches("\\d+\\.?\\d+")) {
							parseData = Float.parseFloat(pro.toString());
						}
						field.setFloat(obj, parseData);
					} else if (double.class.equals(field.getType()) || Double.class.equals(field.getType()))
					{
						double parseData = 0.0;
						if (pro != null && pro.toString().matches("\\d+\\.?\\d+")) {
							parseData = Double.parseDouble(pro.toString());
						}
						field.setDouble(obj, parseData);
					} else if (String.class.equals(field.getType())) {
						if (pro.matches("(%..)+")) {
							pro = URLDecoder.decode(pro, "UTF-8");
						}
						field.set(obj, pro);
					} else if (Date.class.equals(field.getType())) {
						Date value = DateUtils.getDate(pro);
						field.set(obj, value);
					} else if (boolean.class.equals(field.getType()) || Boolean.class.equals(field.getType())) {
						/*
						if (!"1".equals(pro) || !"0".equals(pro)) {
							throw new PageBoleanValueException();
						}
						*/
						field.set(obj, "1".equals(pro) ? true : false);
					}

				} catch (NumberFormatException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IllegalArgumentException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (UnsupportedEncodingException e) {
					e.printStackTrace();
				}

			}


		}
		return obj;

	}
}
